package org.hzz.coupon.infrastructure.repository.mybatis;

import io.gitee.pkmer.convention.converter.RecordAndEntityConverter;
import io.gitee.pkmer.convention.page.PageResponse;
import io.gitee.pkmer.convention.page.query.FilterCondition;
import io.gitee.pkmer.convention.page.query.PageQuery;
import io.gitee.pkmer.convention.repository.nomapper.PageBaseRepository;
import io.gitee.pkmer.util.ReflectUtil;
import lombok.Setter;
import org.hzz.coupon.infrastructure.dao.mapper.coupon.*;
import org.hzz.coupon.infrastructure.dao.model.coupon.Coupon;
import org.hzz.coupon.infrastructure.dao.model.coupon.CouponExample;
import org.hzz.promotions.domain.entity.CouponEntity;
import org.hzz.promotions.domain.repository.CouponRepository;
import org.hzz.promotions.types.constants.CouponFields;
import org.hzz.promotions.types.enums.coupon.CouponStatus;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import org.mybatis.dynamic.sql.SqlColumn;
import org.mybatis.dynamic.sql.insert.render.InsertStatementProvider;
import org.mybatis.dynamic.sql.render.RenderingStrategies;
import org.mybatis.dynamic.sql.select.function.Add;
import org.mybatis.dynamic.sql.select.render.SelectStatementProvider;
import org.mybatis.dynamic.sql.update.render.UpdateStatementProvider;
import org.mybatis.dynamic.sql.where.WhereApplier;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import static org.hzz.coupon.infrastructure.dao.mapper.coupon.CouponDynamicSqlSupport.*;
import static org.mybatis.dynamic.sql.SqlBuilder.*;

/**
 * @author <a href="mailto:1193094618@qq.com">pkmer</a>
 * <br>
 * <a href = "https://gitee.com/pkmer/sonatype-central-publisher">Code Repository</a>
 * At 2024/8/29
 */
@Repository
public class CouponRepositoryImpl
        extends PageBaseRepository<CouponPageMapper,Coupon>
        implements CouponRepository {

    @Setter(onMethod_ = {@Autowired})
    private CouponMapper couponMapper;

    @Setter(onMethod_ = {@Autowired})
    private CouponDynamicMapper couponDynamicMapper;


    @Setter(onMethod_ = {@Autowired})
    private CouponExtMapper couponExtMapper;

    /**
     * {@inheritDoc}
     *
     * @param _coupon
     */
    @Override
    public void insertCoupon(CouponEntity _coupon) {
        Coupon record = Converter.INSTANCE.toRecord(_coupon);
        // 这里的property不是真正的数据库表的列名,是通过反射去拿get方法
        // 所以不能写成 map(coupon.name).toProperty("`name`")
        InsertStatementProvider<Coupon> insertSql = insert(record).into(coupon)
                .map(coupon.id).toProperty("id")
                .map(coupon.name).toProperty("name")
                .map(coupon.discountType).toProperty("discountType")
                .map(coupon.specific).toProperty("specific")
                .map(coupon.discountValue).toProperty("discountValue")
                .map(coupon.thresholdAmount).toProperty("thresholdAmount")
                .map(coupon.maxDiscountAmount).toProperty("maxDiscountAmount")
                .map(coupon.obtainWay).toProperty("obtainWay")
                .map(coupon.totalNum).toProperty("totalNum")
                .map(coupon.userLimit).toProperty("userLimit")
                .map(coupon.creater).toProperty("creater")
                .map(coupon.updater).toProperty("updater")
                .build()
                .render(RenderingStrategies.MYBATIS3);

        /**
         * INSERT INTO coupon (id, `name`, discount_type, `specific`, discount_value
         * 	, threshold_amount, max_discount_amount, obtain_way, total_num, user_limit
         * 	, creater, updater)
         */
        // toProperty 固定 √√√
        couponDynamicMapper.insert(insertSql);

        _coupon.setId(record.getId());
    }

    /**
     * {@inheritDoc}
     * @param coupon 优惠券
     */
    @Override
    public void updateCoupon(CouponEntity coupon) {
        Coupon record = Converter.INSTANCE.toRecord(coupon);
        couponMapper.updateByPrimaryKeySelective(record);
    }

    @Override
    public void batchUpdateCouponEntity(List<CouponEntity> entities) {
        List<Coupon> records = Converter.INSTANCE.toRecords(entities);
        couponExtMapper.updateBatchByPrimarySelective(records);
    }


    /**
     * {@inheritDoc}
     * @param pageQuery 分页
     * @return 分页结果
     */
    @Override
    public PageResponse<CouponEntity> pageQueryCoupon(PageQuery pageQuery){
        PageResponse<Coupon> couponPageResponse = super.pageQuery(pageQuery);
        return Converter.INSTANCE.convertToEntityPage(couponPageResponse);
    }

    /**
     * {@inheritDoc}
     * @param id 优惠券Id
     */
    @Override
    public Optional<CouponEntity> getCouponById(Long id) {
        Optional<Coupon> record = couponDynamicMapper.selectByPrimaryKey(id);
        return record.map(Converter.INSTANCE::toEntity);
    }

    @Override
    public void deleteCoupon(Long id) {
        couponMapper.deleteByPrimaryKey(id);
    }

    /**
     * 增加优惠券的发放数量
     * @param _id 优惠券id
     */
    @Override
    public int incrementIssueNum(long _id,int num) {
        /**
         * UPDATE coupon
         * SET issue_num = issue_num + num
         * WHERE id = 7235968612496969728
         * 	AND issue_num + num <= total_num  // 乐观锁
         */
        Add<Integer> issueNumAdd = add(issueNum, constant(String.valueOf(num)));
        UpdateStatementProvider updateStatementProvider = update(coupon)
                .set(issueNum).equalToConstant(String.format("%s + %d", CouponFields.ISSUE_NUM, num))
                .where(id, isEqualTo(_id))
                .and(issueNumAdd, isLessThanOrEqualTo(totalNum)) // 乐观锁
                .build()
                .render(RenderingStrategies.MYBATIS3);

        logger.info(updateStatementProvider.getUpdateStatement());
        return couponDynamicMapper.update(updateStatementProvider);
    }

    @Override
    public List<CouponEntity> getCouponByIds(List<Long> ids) {
        SelectStatementProvider selectStatementProvider = select(coupon.allColumns())
                .from(coupon)
                .where(id, isIn(ids))
                .build()
                .render(RenderingStrategies.MYBATIS3);

        logger.info(selectStatementProvider.getSelectStatement());
        List<Coupon> records = couponDynamicMapper.selectMany(selectStatementProvider);

        return Converter.INSTANCE.toEntities(records);
    }

    private void test(PageQuery pageQuery){
        List<FilterCondition> filters = pageQuery.getFilters();
        java.lang.reflect.Type type = null;
        Object id_  = 0b111L;
        CouponStatus status_ = CouponStatus.ISSUING;

        WhereApplier whereApplier = where(id, isEqualTo((Long)id_)).and(status, isEqualTo(status_)).toWhereApplier();




        select(coupon.allColumns()).from(coupon).applyWhere(whereApplier);

    }

    public static void main(String[] args) throws IllegalAccessException {
        Map<String, SqlColumn<?>> columnMap = new HashMap<>();
        // 获取 Coupon 类中的所有字段
        Field[] fields = CouponDynamicSqlSupport.class.getDeclaredFields();

        for (Field field : fields) {
            // 确保字段是 SqlColumn 类型
            if (SqlColumn.class.isAssignableFrom(field.getType())) {

                // 获取字段值，即 SqlColumn 对象
                SqlColumn<?> sqlColumn = (SqlColumn<?>) ReflectUtil.getStaticFieldValue(field);

                // 获取字段名
                String columnName = sqlColumn.name();

                // 将字段名和 SqlColumn 对象添加到 Map 中
                columnMap.put(columnName, sqlColumn);
            }
        }
        System.out.println(columnMap);
    }


    public void generateWhereApplier(List<FilterCondition> conditions){




    }

    @Mapper
    interface Converter extends RecordAndEntityConverter<Coupon, CouponEntity> {
        Converter INSTANCE = Mappers.getMapper(Converter.class);
    }
}
